package com.tianji.learning.service.impl;

import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.LearningConstants;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.query.PointsBoardQuery;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author lcm
 * @since 2023-07-29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;


    @Override
    public PointsBoardVO getBoard(PointsBoardQuery query) {
        //1.查询是否是当前赛季
        Long season = query.getSeason();
        //2.查询我的积分和排名
        boolean isCurrent=  season == null || season == 0;
        LocalDateTime now = LocalDateTime.now();
        String key= RedisConstants.BOARD_RECORD_KEY_PREFIX+now.format(DateUtils.POINT_BOARD_SUFFIX_FORMATTER);
        PointsBoard pointsBoard=isCurrent ? queryDefaultSeason(key) : queryHistorySeason(season);
        //3.查询榜单列表
        List<PointsBoard> list=isCurrent ? queryCurrentList(key,query.getPageNo(),query.getPageSize()):queryHistoryList(query);
        //4.封装vo
        //4.1处理我的信息
        PointsBoardVO vo = new PointsBoardVO();
        if(pointsBoard!=null){
            vo.setPoints(pointsBoard.getPoints());
            vo.setRank(pointsBoard.getRank());
        }
        //4.2处理排行榜的信息
        if (CollUtils.isEmpty(list)) {
            return vo;
        }
        //4.3获取用户id集合
        Set<Long> userIds = list.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = new HashMap<>(users.size());
        if(CollUtils.isNotEmpty(users)){
            userMap = users.stream()
                    .collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }

        //5.封装成VO
        List<PointsBoardItemVO> list1 = new ArrayList<>(list.size());
        for (PointsBoard board : list) {
            PointsBoardItemVO vo1 = new PointsBoardItemVO();
            Long userId = board.getUserId();
            UserDTO user = userMap.get(userId);
            if(user!=null){
                vo1.setName(user.getName());
            }
            vo1.setPoints(board.getPoints());
            vo1.setRank(board.getRank());
            list1.add(vo1);
        }
        vo.setBoardList(list1);
        return vo;
    }

    @Override
    public void createPointsBoardTableBySeason(Integer season) {
        getBaseMapper().createPointsBoardTable(LearningConstants.POINTS_BOARD_TABLE_PREFIX + season);
    }

    public PointsBoard queryDefaultSeason(String key) {
        //1.绑定key
        BoundZSetOperations<String, String> ops = redisTemplate.boundZSetOps(key);
        //2.获取分数
        Long userId = UserContext.getUser();
        Double points = ops.score(userId.toString());
        //3.获取排名
        Long rank = ops.reverseRank(userId.toString());
        //4.封装
        PointsBoard pointsBoard = new PointsBoard();
        pointsBoard.setPoints(points == null ? 0 : points.intValue());
        pointsBoard.setRank(rank == null ? 0 : rank.intValue() + 1);
        return pointsBoard;
    }

    public PointsBoard queryHistorySeason(Long season) {
        return null;
    }

    @Override
    public List<PointsBoard> queryCurrentList(String key, Integer pageNo, Integer pageSize) {
        //1.获取分页参数
        int from=(pageNo-1)*pageSize;
        //2.根据键从缓存中读出排行榜数据
        Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().
                reverseRangeByScoreWithScores(key, from, from+pageSize+1);
        //健壮性处理
        if(CollUtils.isEmpty(tuples)){
            return CollUtils.emptyList();
        }
        //3.封装
        int rank=from+1;
        List<PointsBoard> list = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> tuple : tuples) {
            PointsBoard pointsBoard = new PointsBoard();
            Double points = tuple.getScore();
            String userId = tuple.getValue();
            if(userId==null||points==null){
                continue;
            }
            pointsBoard.setUserId(Long.valueOf(userId));
            pointsBoard.setPoints(points.intValue());
            pointsBoard.setRank(rank++);
            list.add(pointsBoard);
        }
        return list;
    }

    public List<PointsBoard> queryHistoryList(PointsBoardQuery query) {
        return null;
    }
}
